<?php
///////////////////////////////////////////////////////////////////////////////////////////////////////
//  这个文件是 JCAT PHP框架的一部，该项目和此文件 均遵循 GNU 自由软件协议
// 
//  Copyleft 2008 JeCat.cn(http://team.JeCat.cn)
//
//
//  JCAT PHP框架 的正式全名是：Jellicle Cat PHP Framework。
//  “Jellicle Cat”出自 Andrew Lloyd Webber的音乐剧《猫》（《Prologue:Jellicle Songs for Jellicle Cats》）。
//  JCAT 是一个开源项目，它像音乐剧中的猫一样自由，你可以毫无顾忌地使用JCAT PHP框架。JCAT 由中国团队开发维护。
//  正在使用的这个版本是：0.4.1 / SVN信息: $Id: class.JCAT_Language.php 1548 2009-03-26 10:38:32Z alee $
//
//
//
//  相关的链接：
//    [主页] http://jcat.JeCat.cn
//    [下载(HTTP)] http://code.google.com/p/jcat-php/downloads/list
//    [下载(svn)] svn checkout http://jcat-php.googlecode.com/svn/branches/0.4.0/Framework/ JCAT0.4
//    [在线文档] http://jcat.JeCat.cn/document
//    [社区] http://jj.jecat.cn/forum-7-1.html
//  不很相关：
//    [MP3] http://www.google.com/search?q=jellicle+songs+for+jellicle+cats+Andrew+Lloyd+Webber
//    [VCD/DVD] http://www.google.com/search?q=CAT+Andrew+Lloyd+Webber+video
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
/*-- Project Introduce --*/

if( !JCAT_Package::ClassExists('JCAT_LanguagePackage') )
	include(dirname(__FILE__).'/class.JCAT_LanguagePackage.php') ;


/**
 * 多语言类，提供基于语言包的多语言处理能力
 *
 * @author		alee
 * @access		public
 */
class JCAT_Language
{
	/**
	 * 构造函数，无法直接访问，只能通过 JCAT_Language::GetLanguage() 创建对象
	 * 
	 * @access	public
	 * @param	$sLanguageName	string	语言名称
	 * @static
	 * @return	void
	 */
	private function JCAT_Language($sLanguageName)
	{
		$this->sLanguageName = $sLanguageName ;
	}




	/**
	 * 根据语言名称，创建 或 取得已创建 的 语言实例（享元模式）
	 * 
	 * @access	public
	 * @param	$sLanguageName	string	语言名称
	 * @static
	 * @return	JCAT_Language
	 */
	static public function GetLanguage(  $sLanguageName ) 
	{
		if( isset(self::$arrLanguageInses[$sLanguageName]) )
		{
			return self::$arrLanguageInses[$sLanguageName] ;
		}
			
		$aLanguage = new JCAT_Language($sLanguageName) ;
		self::$arrLanguageInses[$sLanguageName] = $aLanguage ;
		
		// 若无当前语言实例,自动 设置为 当前语言实例
		if( !self::$aCurrentLanguage )
		{
			self::$aCurrentLanguage = $aLanguage ;
		}
		
		return $aLanguage ;
	}

	/**
	 * 设置当前语言包
	 * 
	 * @access	public
	 * @param	$Language	JCAT_Language,string	语言实例，或语言名称
	 * @static
	 * @return	old_value
	 */
	static public function SetCurrentLanguage( $Language ) 
	{

		$old_value = self::GetCurrentLanguage() ;

		JCAT_ASSERT::ASSERT_ISTHESE($Language,array('string','JCAT_Language'),'参数 $Language 必须为语言名称(string 类型)，或已创建的语言实例(JCAT_Language对象)') ;

		if( is_string($Language) )
		{
			self::$aCurrentLanguage = self::GetLanguage($Language) ;
		}
		elseif( JCAT_Global::IsKindOf('JCAT_Language') )
		{
			self::$aCurrentLanguage = $Language ;
		}
		else
		{
			JCAT_ASSERT::ASSERT_(0,'?!') ;
		}

		return $old_value ;
	}



	/**
	 * 返回当前语言包
	 * 
	 * @access	public
	 * @static
	 * @return	JCAT_Language
	 */
	static public function GetCurrentLanguage(  ) 
	{
		return self::$aCurrentLanguage ;
	}


	/**
	 * 返回语言包名称
	 * 
	 * @access	public
	 * @return	string
	 */
	public function GetLanguageName() 
	{
		return $this->sLanguageName ;
	}



	/**
	 * 创建 或 取得 已创建的 语言包
	 * 
	 * @access	public
	 * @param	$sPackageName	string	语言包名称
	 * @return	JCAT_LanguagePackage
	 */
	public function GetPackage( $sPackageName ) 
	{
		$thePackage = JCAT_LanguagePackage::GetPackage($this->GetLanguageName(),$sPackageName) ;
		if( !$thePackage )
		{
			throw new JCAT_Exception("根据参数 \$sPackageName({$sPackageName}) 无法找到语言包。",JCAT_Exception::MakeExceptionCode(__CLASS__,1)) ;
		}
		
		// 若无当前语言包，自动设为当前语言包
		if( !$this->GetCurrentPackage() )
		{
			$this->SetCurrentPackage( $thePackage ) ;
		}
		
		return $thePackage ;
	}


	
	/**
	 * 返回当前语言包
	 * 
	 * @access	public
	 * @return	JCAT_LanguagePackage,null
	 */
	public function GetCurrentPackage() 
	{
		return $this->aCurrentPackageIns ;
	}



	/**
	 * 设置当前语言包
	 * 
	 * @access	public
	 * @param	$Package	string,JCAT_LanguagePackage		语言包名称 或 已创建的实例
	 * @return	old_value
	 */
	public function SetCurrentPackage( $Package ) 
	{
		$old_value = $this->GetCurrentPackage() ;
		JCAT_ASSERT::ASSERT_ISTHESE($Package,array('string','JCAT_LanguagePackage'),'参数 $Package 必须为语言包名称,文件名,完整路径(string 类型)，或已创建的语言包对象(JCAT_LanguagePackage 类型)') ;
		
		if( is_string($Package) )
		{
			$this->aCurrentPackageIns = $this->GetPackage($Package) ;
		}
		else
		{
			$this->aCurrentPackageIns = $Package ;
		}

		return $old_value ;		
	}


	/**
	 * 根据语句内容产生Key
	 * 
	 * @access	public
	 * @param	$sSentence	string	语句内容
	 * @static
	 * @return	string	
	 */
	static public function MakeSentenceKey( $sSentence ) 
	{
		return md5($sSentence) ;
	}



	/**
	 * 从当前语言的当前语言包取得一条语句
	 * 
	 * @access	public
	 * @param	$sSentence		string	语句
	 * @param	Argvs... ...	mixed	参数
	 * @return	string
	 */
	static public function Sentence(  $sSentence  /* Argvs... ...*/ ) 
	{
		$arrArgs = func_get_args() ;
		unset($arrArgs[0]) ;
		array_unshift($arrArgs,$sSentence,null,null) ;
		
		return call_user_func_array( array(__CLASS__,'SentenceEx'), $arrArgs ) ;
	}



	/**
	 * 从指定语言的指定语言包取得一条语句
	 * 
	 * @access	public
	 * @param	$sSentence		sting								原始语句
	 * @param	$Package		string,JCAT_LanguagePackage,null	语言包名称、语言包实例 或 null(使用当前语言包)
	 * @param	$Language		string,JCAT_Language,null			语言名称、语言实例 或 null(使用当前语言)
	 * @param	Argvs... ...	mixed									代入语句的参数
	 * @return	string
	 */
	static public function SentenceEx(  $sSentence,  $Package,  $Language=null /* Argvs... ...*/ ) 
	{
		// 参数类型检验 ...
		JCAT_ASSERT::ASSERT_STRING($sSentence,'参数 $sSentence 必须为 string 类型') ;
		JCAT_ASSERT::ASSERT_ISTHESE($Language,array('null','string','JCAT_LanguagePackage'),'null','参数 $Language 必须为 语言名称(string 类型)，已创建的语言对象(JCAT_Language 类型)，或 null（使用当前语言）') ;
		JCAT_ASSERT::ASSERT_ISTHESE($Package,array('string','JCAT_Language','null'),'参数 $Package 必须为 语言包名称(string 类型)，已创建的语言包对象(JCAT_LanguagePackage 类型)，或 null（使用当前语言包）') ;
		
		
		// 语句 Key
		$sSentenceKey = self::MakeSentenceKey($sSentence) ;
		
		
		// 取得 语言享员对象
		// ---------------------------
		// 语言名称
		if( is_string($Language) )
		{
			$theLanguage = self::GetLanguage($Language) ;
		}
		
		// 已创建的语言对象
		elseif( is_object($Language) )
		{
			$theLanguage = $Language ;
		}
		
		// 缺省：当前语言对象
		elseif( $Language===null )
		{
			$theLanguage = self::GetCurrentLanguage() ;
			if(!$theLanguage)
			{
				throw new JCAT_Exception("尚未指定当前语言。",JCAT_Exception::MakeExceptionCode(__CLASS__,2)) ;
			}
		}
		
		JCAT_ASSERT::ASSERT_($theLanguage,'!?... ... what is wrong?') ;
		
		
		// 取得 语言包 享员对象
		// ---------------------------
		// 语言包 名称
		if( is_string($Package) )
		{
			$thePackage = $theLanguage->GetPackage($Package) ;
		}

		// 已创建的语言包对象
		elseif( is_object($Package) )
		{
			$thePackage = $Package ;
		}
			
		// 缺省：当前语言包对象
		elseif( $Package===null )
		{
			$thePackage = $theLanguage->GetCurrentPackage() ;
			if(!$thePackage)
			{
				throw new JCAT_Exception("尚未指定当前语言包。",JCAT_Exception::MakeExceptionCode(__CLASS__,3)) ;
			}
		}
		
		JCAT_ASSERT::ASSERT_($thePackage,'!?... ... what is wrong?') ;
		
		
		
		// 语句存在
		if($thePackage->Has($sSentenceKey))
		{
			$sRealSentence = $thePackage->Get($sSentenceKey) ;
		}
		
		// 语句不存在，使用原文
		else
		{
			$sRealSentence = $sSentence ;
			$thePackage->Set($sSentenceKey, $sRealSentence) ;
		}
		
		
		// 代入参数
		if( func_num_args() > 3 )
		{
			$arrArgs = func_get_args() ;
			$arrArgs[0] = $sRealSentence ;
			unset($arrArgs[1],$arrArgs[2]) ;
			
			// 将参数中为null的参数转换成字串'Null'
			foreach ($arrArgs as $nIdx=>&$Arg)
			{
				if( $nIdx>0 and $Arg===null )
				{
					$Arg = 'Null' ;
				}
			}
			$sRealSentence = call_user_func_array('sprintf',$arrArgs) ;
		}
		
		
		return $sRealSentence ;
		
	}




	// 属性 ///////////////////////////////////////////////////////////////////////////////

	/**
	 * 当前语言
	 * 
	 * @access	public
	 * @var		const
	 */
	const CURRENT_LANGUAGE = null ;
	
	
	/**
	 * 语言名称
	 * 
	 * @access	private
	 * @var		string
	 */
	private $sLanguageName ;


	/**
	 * 当前语言包
	 * 
	 * @access	private
	 * @var		JCAT_LanguagePackage
	 */
	private $aCurrentPackageIns = null ;

	/**
	 * 已创建的语言实例（享元模式）
	 * 
	 * @access	private
	 * @var		array
	 * @static
	 */
	static private $arrLanguageInses ;

	/**
	 * 当前语言实例
	 * 
	 * @access	private
	 * @var		JCAT_Language
	 * @static
	 */
	static private $aCurrentLanguage ;
	
}
/*macro_exception_code:3*/
?>